/* ------------------------------------------------------------------
 * Date.prototype.Format
 * 格式化日期时间
 * 用法：new Date().Format('yyyy-MM-dd HH:mm:ss')
 * ------------------------------------------------------------------ */
if (!Date.prototype.Format) {
  Date.prototype.Format = function (fmt) {
    const o = {
      'M+': this.getMonth() + 1,                 // 月份
      'd+': this.getDate(),                      // 日
      'H+': this.getHours(),                     // 小时
      'm+': this.getMinutes(),                   // 分
      's+': this.getSeconds(),                   // 秒
      'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
      S: this.getMilliseconds()                  // 毫秒
    };

    // 年份单独处理
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(
        RegExp.$1,
        (this.getFullYear() + '').substr(4 - RegExp.$1.length)
      );
    }

    // 其余占位符统一处理
    for (const k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) {
        fmt = fmt.replace(
          RegExp.$1,
          RegExp.$1.length === 1
            ? o[k]
            : ('00' + o[k]).substr(('' + o[k]).length)
        );
      }
    }

    return fmt;
  };
};

const utils = {
  sleep: (ms) => {
    return new Promise((resolve) => setTimeout(resolve, ms))
  },
  formatBeijingDateTime: (date) => {
    const beijingDate = new Date(date.getTime() + 8 * 60 * 60 * 1000);
    return beijingDate.toISOString().replace('T', ' ').substring(0, 19);
  },
  adjustToStep: (value, stepSize) => {
    if (!stepSize || isNaN(stepSize) || !isFinite(stepSize)) return value;
    const precision = Math.floor(Math.log10(1 / parseFloat(stepSize)));
    const factor = Math.pow(10, precision);
    return Math.floor(value * factor) / factor;
  },
  retry(fn, times, interval) {
    interval = interval || 0;
    times = times || 3;
    return new Promise((resolve, reject) => {
      const attempt = () => {
        fn().then(res => {
          resolve(res);
        }, async (err) => {
          // 记录重试次数
          if (times !== 0) {
            times--;
            setTimeout(attempt, interval);
          } else {
            reject(err);
          }
        })
      }
      attempt();
    });
  },
  randomStr: (len, charSet) => {
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var randomString = '';
    for (var i = 0; i < len; i++) {
      var randomPoz = Math.floor(Math.random() * charSet.length);
      randomString += charSet.substring(randomPoz, randomPoz + 1);
    }
    return randomString;
  },

  // 解析命令行参数
  arguments(argName) {
    const arg = process.argv.find(a => a.startsWith(`--${argName}=`));
    if (arg) {
      return arg.split('=')[1];
    }
    return null;
  },

  /**
 * 批量获取当天 0 点时间戳
 * @param {string[]} timeZones 时区数组，如 ['UTC', 'Asia/Shanghai', 'America/New_York']
 * @returns {number[]} 与入参顺序一一对应的时间戳数组
 */
  getTodayZeroTimestamps(timeZones) {
    return timeZones.map(tz => {
      // 获取指定时区的今天日期
      const parts = new Intl.DateTimeFormat('en-CA', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        timeZone: tz,
      }).formatToParts(new Date());

      const y = parts.find(p => p.type === 'year').value;
      const m = parts.find(p => p.type === 'month').value;
      const d = parts.find(p => p.type === 'day').value;

      // 直接构造该时区今天0点的时间戳
      // 使用简化方法：先获取UTC的0点，再加上时区偏移
      const utcMidnight = Date.UTC(+y, +m - 1, +d, 0, 0, 0, 0);

      // 计算时区偏移（通过对比同一时刻在不同时区的表示）
      const testTime = new Date();
      const utcTime = new Date(testTime.toLocaleString('sv-SE', {timeZone: 'UTC'}));
      const tzTime = new Date(testTime.toLocaleString('sv-SE', {timeZone: tz}));
      const offset = utcTime.getTime() - tzTime.getTime();

      return utcMidnight + offset;
    });
  },

  formatKline: (info) => {
    const symbol = info.data.ps; // 交易对
    const rate = (info.data.k.c - info.data.k.o) / info.data.k.o * 100;
    const time = utils.formatBeijingDateTime(new Date(info.data.k.t));
    const high = info.data.k.h;
    const close = info.data.k.c;
    const open = info.data.k.o;
    const closeToHigh = ((high - close) / open) * 100;
    return { ...info.data, symbol, rate, time, closeToHigh, high, close, open };
  }
}

export default utils;
